home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / sipp / libsipp / lightsou.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-17  |  10.5 KB  |  459 lines

  1. /**
  2.  ** sipp - SImple Polygon Processor
  3.  **
  4.  **  A general 3d graphic package
  5.  **
  6.  **  Copyright Equivalent Software HB  1992
  7.  **
  8.  ** This program is free software; you can redistribute it and/or modify
  9.  ** it under the terms of the GNU General Public License as published by
  10.  ** the Free Software Foundation; either version 1, or any later version.
  11.  ** This program is distributed in the hope that it will be useful,
  12.  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  ** GNU General Public License for more details.
  15.  ** You can receive a copy of the GNU General Public License from the
  16.  ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  **/
  18.  
  19. /**
  20.  ** lightsource.c - Functions that handles lightsources.
  21.  **/
  22.  
  23. #include <stdio.h>
  24. #include <values.h>
  25.  
  26. #include <geometric.h>
  27. #include <lightsource.h>
  28. #include <sipp.h>
  29. #include <smalloc.h>
  30.  
  31.  
  32. Lightsource  *lightsrc_stack;  /* Stack of installed lightsources. */
  33.  
  34. extern int depthmap_size;
  35.  
  36. static int    rand_index = 0;
  37. static double rand_no[256];
  38.  
  39. static double shadow_sample();
  40.  
  41.  
  42. /*
  43.  * Create a new lightsource in the scene.
  44.  */
  45. Lightsource *
  46. lightsource_create(x, y, z, red, grn, blu, type)
  47.     double  x, y, z;
  48.     double  red, grn, blu;
  49.     int     type;
  50. {
  51.     Lightsource    *lp;
  52.     Dir_light_info *ip;
  53.  
  54.     if (type != LIGHT_DIRECTION && type != LIGHT_POINT) {
  55.         return NULL;
  56.     }
  57.  
  58.     lp = (Lightsource *)scalloc(1, sizeof(Lightsource));
  59.     ip = (Dir_light_info *)scalloc(1, sizeof(Dir_light_info));
  60.  
  61.     MakeVector(ip->dir, x, y, z);
  62.     if (type == LIGHT_DIRECTION) {
  63.         vecnorm(&ip->dir);
  64.     }
  65.     lp->info = (void *)ip;
  66.     
  67.     lp->type = type;
  68.     lp->color.red = red;
  69.     lp->color.grn = grn;
  70.     lp->color.blu = blu;
  71.     lp->active = TRUE;
  72.     lp->next = lightsrc_stack;
  73.     lp->shadow.active = FALSE;
  74.     lightsrc_stack = lp;
  75.  
  76.     return lp;
  77. }
  78.  
  79.  
  80. /*
  81.  * Change the position of a lightsource. If it is a directional
  82.  * lightsource it's direction is changed.
  83.  */
  84. void
  85. lightsource_put(lp, x, y, z)
  86.     Lightsource *lp;
  87.     double       x, y, z;
  88. {
  89.     if (lp->type != LIGHT_DIRECTION && lp->type != LIGHT_POINT) {
  90.         return;
  91.     }
  92.  
  93.     MakeVector(((Dir_light_info *)(lp->info))->dir, x, y, z);
  94.     if (lp->type == LIGHT_DIRECTION) {
  95.         vecnorm(&((Dir_light_info *)(lp->info))->dir);
  96.     }
  97. }
  98.     
  99.  
  100. /*
  101.  * Define a new spotlight in the scene.
  102.  */
  103. Lightsource *
  104. spotlight_create(x, y, z, to_x, to_y, to_z, fov, red, grn, blu, type, shadows)
  105.     double  x, y, z;
  106.     double  to_x, to_y, to_z;
  107.     double  fov;
  108.     double  red, grn, blu;
  109.     int     type;
  110.     bool    shadows;
  111. {
  112.     Lightsource     *lp;
  113.     Spot_light_info *sp;
  114.     Vector           tmp;
  115.  
  116.     if (type != SPOT_SHARP && type != SPOT_SOFT) {
  117.         return NULL;
  118.     }
  119.  
  120.     lp = (Lightsource *)scalloc(1, sizeof(Lightsource));
  121.     sp = (Spot_light_info *)scalloc(1, sizeof(Spot_light_info));
  122.  
  123.     MakeVector(sp->pos, x, y, z);
  124.     MakeVector(sp->point, to_x, to_y, to_z);
  125.     VecSub(sp->dir, sp->point, sp->pos);
  126.     vecnorm(&sp->dir);
  127.     sp->cos_fov = cos(fov * M_PI / 180.0 * 0.5);
  128.     lp->info = (void *)sp;
  129.     
  130.     lp->shadow.fov_factor = tan(fov * M_PI / 180.0 * 0.5);
  131.     lp->shadow.active = shadows;
  132.     lp->shadow.d_map = NULL;
  133.  
  134.     lp->type = type;
  135.     lp->color.red = red;
  136.     lp->color.grn = grn;
  137.     lp->color.blu = blu;
  138.     lp->active = TRUE;
  139.     lp->next = lightsrc_stack;
  140.     lightsrc_stack = lp;
  141.  
  142.     return lp;
  143. }
  144.  
  145.  
  146. /*
  147.  * Remove the lightsource LIGHT from the list of lights and free all 
  148.  * resources attached to it.
  149.  */
  150. void
  151. light_destruct(light)
  152.     Lightsource   *light;
  153. {
  154.     Lightsource  * lght;
  155.  
  156.     /* First,  we must remove the light from the list of active lights. */
  157.     while (lightsrc_stack == light)
  158.     lightsrc_stack = lightsrc_stack->next;
  159.  
  160.     lght = lightsrc_stack;
  161.     while (lght != NULL) {
  162.     if (lght->next == light)
  163.         lght->next = lght->next->next;
  164.     else
  165.         lght = lght->next;
  166.     }
  167.  
  168.     sfree(light->info);
  169.     sfree(light);
  170. }
  171.  
  172.  
  173. /*
  174.  * Change the position of a spotlight.
  175.  */
  176. void 
  177. spotlight_pos(lp, x, y, z)
  178.     Lightsource *lp;
  179.     double       x, y, z;
  180. {
  181.     Spot_light_info *sp;
  182.  
  183.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  184.         return;
  185.     }
  186.  
  187.     sp = (Spot_light_info *)(lp->info);
  188.     MakeVector(sp->pos, x, y, z);
  189.     VecSub(sp->dir, sp->point, sp->pos);
  190.     vecnorm(&sp->dir);
  191. }
  192.  
  193.  
  194. /*
  195.  * Change the point a spotlight is shining at.
  196.  */
  197. void 
  198. spotlight_at(lp, x, y, z)
  199.     Lightsource *lp;
  200.     double       x, y, z;
  201. {
  202.     Spot_light_info *sp;
  203.  
  204.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  205.         return;
  206.     }
  207.  
  208.     sp = (Spot_light_info *)(lp->info);
  209.     MakeVector(sp->point, x, y, z);
  210.     VecSub(sp->dir, sp->point, sp->pos);
  211.     vecnorm(&sp->dir);
  212. }
  213.  
  214.  
  215. /*
  216.  * Change the opening angle of a spotlight.
  217.  */
  218. void 
  219. spotlight_opening(lp, fov)
  220.     Lightsource *lp;
  221.     double       fov;
  222. {
  223.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  224.         return;
  225.     }
  226.  
  227.     ((Spot_light_info *)(lp->info))->cos_fov = cos(fov * M_PI / 180.0 * 0.5);
  228. }
  229.  
  230.  
  231. /*
  232.  * Turn on or off shadow generation from a spotlight.
  233.  */
  234. void 
  235. spotlight_shadows(lp, flag)
  236.     Lightsource *lp;
  237.     bool         flag;
  238. {
  239.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  240.         return;
  241.     }
  242.  
  243.     lp->shadow.active = flag;
  244. }
  245.  
  246.     
  247. /*
  248.  * Set the color of the light from a lightsource or a spotlight.
  249.  */
  250. void light_color(lp, red, grn, blu)
  251.     Lightsource *lp;
  252.     double       red, grn, blu;
  253. {
  254.     lp->color.red = red;
  255.     lp->color.grn = grn;
  256.     lp->color.blu = blu;
  257. }
  258.     
  259.  
  260. /*
  261.  * Turn a lightsource or spotlight on or off.
  262.  */
  263. void 
  264. light_active(lp, flag)
  265.     Lightsource *lp;
  266.     bool         flag;
  267. {
  268.     lp->active = flag;
  269. }
  270.  
  271.  
  272. /*
  273.  * Evaluate how much light from the lightsource LP thas is falling
  274.  * on the point POS. Type of lightsource and shadows are taken into
  275.  * account.
  276.  * In VEC we return a vector pointing from POS to LP.
  277.  */
  278. double
  279. light_eval(lp, pos, vec)
  280.     Lightsource *lp;
  281.     Vector      *pos;
  282.     Vector      *vec;
  283. {
  284.     double fov_factor;
  285.  
  286.     switch (lp->type) {
  287.       case LIGHT_DIRECTION:
  288.         VecCopy(*vec, ((Dir_light_info *)(lp->info))->dir);
  289.         return 1.0;
  290.  
  291.       case LIGHT_POINT:
  292.         VecSub(*vec, ((Dir_light_info *)(lp->info))->dir, *pos);
  293.         vecnorm(vec);
  294.         return 1.0;
  295.  
  296.       case SPOT_SOFT:
  297.         VecSub(*vec, *pos, ((Spot_light_info *)(lp->info))->pos);
  298.         vecnorm(vec);
  299.  
  300.         fov_factor = VecDot(*vec, ((Spot_light_info *)(lp->info))->dir);
  301.         if (fov_factor <= 0.0
  302.             || fov_factor < ((Spot_light_info *)(lp->info))->cos_fov)
  303.         {
  304.             VecNegate(*vec);
  305.             return 0.0;
  306.  
  307.         } else {
  308.             fov_factor = (cos((1.0 - fov_factor) * M_PI 
  309.                               / (1.0 - ((Spot_light_info *)
  310.                                         (lp->info))->cos_fov))  
  311.                           * 0.5 + 0.5);
  312.             if (lp->shadow.active && lp->shadow.d_map) {
  313.                 VecNegate(*vec);
  314.                 return fov_factor * shadow_sample(&lp->shadow, pos);
  315.  
  316.             } else {
  317.                 VecNegate(*vec);
  318.                 return fov_factor;
  319.             }
  320.         } 
  321.  
  322.       case SPOT_SHARP:
  323.         VecSub(*vec, *pos, ((Spot_light_info *)(lp->info))->pos);
  324.         vecnorm(vec);
  325.  
  326.         if (VecDot(*vec, ((Spot_light_info *)(lp->info))->dir) 
  327.             < ((Spot_light_info *)(lp->info))->cos_fov) 
  328.         {
  329.             VecNegate(*vec);
  330.             return 0.0;
  331.  
  332.         } else if (lp->shadow.active && lp->shadow.d_map) {
  333.             VecNegate(*vec);
  334.             return shadow_sample(&lp->shadow, pos);
  335.  
  336.         } else {
  337.             VecNegate(*vec);
  338.             return 1.0;
  339.         }
  340.     }
  341. }
  342.  
  343.  
  344. /*
  345.  * Sample a depth map and do percentage closer filtering to
  346.  * see how much shadowed POS is.
  347.  */
  348. #define BOXRES  0.002
  349. static double
  350. shadow_sample(sh, pos)
  351.     Shadow_info *sh;
  352.     Vector      *pos;
  353. {
  354.     Vector   lp_view;
  355.     int      lit;
  356.     int      ns;
  357.     int      x, y;
  358.     int      i, j;
  359.     double   lu, hu;
  360.     double   lv, hv;
  361.     double   xmin, ymin;
  362.     double   boxres;
  363.     double   ds, js;
  364.     double   persp;
  365.  
  366.     point_transform(&lp_view, pos, &sh->matrix);
  367.     persp = lp_view.z * sh->fov_factor;
  368.     lp_view.x = (lp_view.x * depthmap_size * 0.5 / persp
  369.                  + depthmap_size * 0.5);
  370.     lp_view.y = (lp_view.y * depthmap_size * 0.5 / persp
  371.                  + depthmap_size * 0.5);
  372.     
  373.     boxres = BOXRES * depthmap_size;
  374.     lu = floor(lp_view.x - boxres);
  375.     lv = floor(lp_view.y - boxres);
  376.     hu = ceil(lp_view.x + boxres);
  377.     hv = ceil(lp_view.y + boxres);
  378.     if (lu >= depthmap_size || hu < 0.0
  379.         || lv >= depthmap_size || hv < 0.0) 
  380.     {
  381.         return 1.0;
  382.     }
  383.  
  384.     ns = (int)(boxres * 2.0 + 0.5);
  385.  
  386.     ds = 2.0 * boxres / ns;
  387.     js = ds * 0.5;
  388.  
  389.     xmin = lp_view.x - boxres + js;
  390.     ymin = lp_view.y - boxres + js;
  391.  
  392.     lit = ns * ns;
  393.     for (i = 0, lp_view.x = xmin; i < ns; i++, lp_view.x += ds) {
  394.         for (j = 0, lp_view.y = ymin; j < ns; j++, lp_view.y += ds) {
  395.             rand_index = (rand_index + 1) & 255;
  396.             x = lp_view.x + rand_no[rand_index] * js;
  397.             rand_index = (rand_index + 1) & 255;
  398.             y = lp_view.y + rand_no[rand_index] * js;
  399.             if (x >= 0 && x < depthmap_size 
  400.                 && y >= 0 && y < depthmap_size) {
  401.                 if (lp_view.z > (sh->d_map[(depthmap_size - 1 - y) 
  402.                                            * depthmap_size + x] 
  403.                                  + sh->bias)) {
  404.                     lit--;
  405.                 }
  406.             }
  407.         }
  408.         
  409.     }
  410.  
  411.    return (double)lit / (double)(ns * ns);
  412. }
  413.  
  414.  
  415. /*
  416.  * Create and initialize depthmaps for all lightsources
  417.  * that have their shadow generation activated.
  418.  */
  419. void
  420. depthmaps_create()
  421. {
  422.     Lightsource *lp;
  423.     int          i;
  424.  
  425.     for (i = 0; i < 256; i++) {
  426.         rand_no[i] = (RANDOM() + 1.0) * 0.5;
  427.     }
  428.     rand_index = 0;
  429.     for (lp = lightsrc_stack; lp != NULL; lp = lp->next) {
  430.         if (lp->shadow.active) {
  431.             if (NULL != lp->shadow.d_map) {
  432.                 sfree(lp->shadow.d_map);
  433.             }
  434.             lp->shadow.d_map = (float *)smalloc(depthmap_size * depthmap_size
  435.                                                 * sizeof(float));
  436.             for (i = 0; i < depthmap_size * depthmap_size; i++) {
  437.                 lp->shadow.d_map[i] = (float)MAXFLOAT;
  438.             }
  439.         }
  440.     }
  441. }
  442.    
  443.  
  444. /*
  445.  * Release the memory used by the depthmaps.
  446.  */
  447. void
  448. depthmaps_destruct()
  449. {
  450.     Lightsource *lp;
  451.  
  452.     for (lp = lightsrc_stack; lp != NULL; lp = lp->next) {
  453.         if (lp->shadow.active && lp->shadow.d_map != NULL) {
  454.             sfree(lp->shadow.d_map);
  455.             lp->shadow.d_map = NULL;
  456.         }
  457.     }
  458. }
  459.